package com.example.java_gobang.api;

import com.example.java_gobang.game.OnlineUserManager;
import com.example.java_gobang.game.RoomManager;
import com.example.java_gobang.model.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

@Slf4j
@Component
public class GameAPI extends TextWebSocketHandler {

    @Autowired
    private RoomManager roomManager;

    @Autowired
    private OnlineUserManager onlineUserManager;

    @Autowired
    private UserMapper userMapper;

    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("进入玩家对战房间");
        GameReadyResponse gameReadyResponse = new GameReadyResponse();
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            gameReadyResponse.setOk(false);
            gameReadyResponse.setReason("用户未登录！");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsBytes(gameReadyResponse)));
            session.close();
            return;
        }
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            gameReadyResponse.setOk(false);
            gameReadyResponse.setReason("用户未匹配到!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(gameReadyResponse)));
            return;
        }
        if (onlineUserManager.getFromGameHall(user.getUserId()) != null || onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
            gameReadyResponse.setOk(true);
            gameReadyResponse.setReason("禁止一个账号多开游戏页面!");
            gameReadyResponse.setMessage("repeatConnection");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(gameReadyResponse)));
            session.close();
            return;
        }
        onlineUserManager.enterGameRoom(user.getUserId(), session);
        log.info("玩家 "+ user.getUsername() + "加入游戏");
        synchronized (room) {
            if (room.getUser1() == null) {
                room.setUser1(user);
                room.setWhiteUserId(user.getUserId());
                log.info("玩家" + user.getUsername() + "准备就绪! 作为玩家1");
                return;
            }
            if (room.getUser2() == null) {
                room.setUser2(user);
                log.info("玩家" + user.getUsername() + "准备就绪! 作为玩家2");

                //服务器通知两个玩家，游戏双方已经准备就绪
                noticeGameReady(room, room.getUser1(), room.getUser2());
                noticeGameReady(room, room.getUser2(), room.getUser1());
                return;
            }
        }
        gameReadyResponse.setOk(false);
        gameReadyResponse.setReason("当前房间已满");
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(gameReadyResponse)));
    }

    private void noticeGameReady(Room room, User thisUser, User thatUser) throws IOException {
        GameReadyResponse gameReadyResponse = new GameReadyResponse();
        gameReadyResponse.setOk(true);
        gameReadyResponse.setReason("");
        gameReadyResponse.setMessage("gameReady");
        gameReadyResponse.setRoomId(room.getRoomId());
        gameReadyResponse.setThisUserId(thisUser.getUserId());
        gameReadyResponse.setThatUserId(thatUser.getUserId());
        gameReadyResponse.setWhiteUser(room.getWhiteUserId());
        gameReadyResponse.setThatUserName(thatUser.getUsername());
        WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(thisUser.getUserId());
        webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(gameReadyResponse)));
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        User user = (User) session.getAttributes().get("user");
        Room room = roomManager.getRoomByUserId(user.getUserId());
        String payload = (String) message.getPayload();
        GameRequest gameRequest = objectMapper.readValue(payload, GameRequest.class);
        room.putChess(gameRequest);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        User user = (User) session.getAttributes().get("user");
        WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (webSocketSession == session) {
            log.info("玩家id :" + user.getUserId() + "异常");
            onlineUserManager.exitGameRoom(user.getUserId());
            noticeThatUser(user);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        User user = (User) session.getAttributes().get("user");
        WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(user.getUserId());
        if (webSocketSession == session) {
            log.info("玩家id :" + user.getUserId() + "掉线");
            onlineUserManager.exitGameRoom(user.getUserId());
            noticeThatUser(user);
        }
    }

    private void noticeThatUser(User user) throws IOException {
        log.info("noticeThatUser");
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            return;
        }
        //根据房间找到对手
        User thatUser = room.getUser1() == user ? room.getUser2() : room.getUser1();

        //找到对手在线状态
        WebSocketSession session = onlineUserManager.getFromGameRoom(thatUser.getUserId());
        if (session == null) {
            //对手也掉线了，无需通知
            return;
        }

        //构造一个响应, 来通知对手, 你是获胜方
        GameResponse gameResponse = new GameResponse();
        gameResponse.setUserId(thatUser.getUserId());
        gameResponse.setMessage("putChess");
        gameResponse.setWinner(thatUser.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(gameResponse)));

        //更新玩家的分数信息
        int winUserId = thatUser.getUserId();
        int loseUserId = user.getUserId();
        userMapper.userWin(winUserId);
        userMapper.userLose(loseUserId);

        //释放房间对象
        roomManager.remove(room.getRoomId(), room.getUser1().getUserId(), room.getUser2().getUserId());
    }
}
